package com.leyou.trade.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.auth.constants.JwtConstants;
import com.leyou.auth.utils.UserContext;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.item.clients.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.trade.dto.OrderFormDTO;
import com.leyou.trade.entity.Order;
import com.leyou.trade.entity.OrderDetail;
import com.leyou.trade.entity.OrderLogistics;
import com.leyou.trade.entity.enums.OrderStatus;
import com.leyou.trade.mapper.OrderMapper;
import com.leyou.trade.service.OrderDetailService;
import com.leyou.trade.service.OrderLogisticsService;
import com.leyou.trade.service.OrderService;
import com.leyou.trade.utils.PayHelper;
import com.leyou.trade.utils.TokenContext;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.trade.constants.PayConstants.ORDER_NO_KEY;
import static com.leyou.trade.constants.PayConstants.TOTAL_FEE_KEY;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderLogisticsService orderLogisticsService;
    @Autowired
    private UserClient userClient;
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private PayHelper payHelper;
    @Override
    @Transactional

    public Long createOrder(OrderFormDTO orderFormDTO, HttpServletRequest request) {

        //从请求中的cookie中获取到token信息存入我们设计的tokenContext
        TokenContext.setToken(CookieUtils.getCookieValue(request, JwtConstants.COOKIE_NAME));

        //key:skuId,value:num
        Map<Long, Integer> cartsMap = orderFormDTO.getCarts();

        //提交的要购买的商品的数量
        int size = cartsMap.size();
        //订单保存，三张表
        //order

        //根据skuId集合查询对应的商品库中sku的集合
        List<SkuDTO> skuDTOS = this.itemClient.querySkuByIds(
                new ArrayList<>(cartsMap.keySet()));


        //提交的数量，和能查到的数量不匹配，则表示下单出了系统故障，此时，应该停止下单操作
        if (size != skuDTOS.size()) {
            throw new LyException(500, "下单商品出现异常请重新提交");
        }

        //减库存业务
        try {
            this.itemClient.minusStock(cartsMap);
        } catch (FeignException e) {
            throw new LyException(e.status(), e.getMessage());
        }

        //TODO 匹配库存，如果某个商品要购买的数量大于库存数量一定不能下单

        Order order = new Order();

        long totalFee = 0;

        //计算总价
        //totalFee skuPrice*num+skuPrice*num
        for (SkuDTO skuDTO : skuDTOS) {
            Long skuId = skuDTO.getId();
            Integer num = cartsMap.get(skuId);
            totalFee += skuDTO.getPrice() * num;
        }


        //封装order
        order.setTotalFee(totalFee);
        order.setActualFee(totalFee);
        order.setPaymentType(orderFormDTO.getPaymentType());
        order.setPostFee(0L);
        order.setUserId(UserContext.getUser().getId());
        order.setStatus(1);

        //order保存
        save(order);


        //orderDetail
        //订单详情封装  查询到的skuDTO转为OrderDetail
        List<OrderDetail> orderDetailList = skuDTOS.stream().map(skuDTO -> {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(order.getOrderId());
            orderDetail.setSkuId(skuDTO.getId());
            orderDetail.setNum(cartsMap.get(skuDTO.getId()));
            orderDetail.setSpec(skuDTO.getSpecialSpec());
            orderDetail.setTitle(skuDTO.getTitle());
            orderDetail.setPrice(skuDTO.getPrice());
            orderDetail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
            return orderDetail;
        }).collect(Collectors.toList());

        //批量保存orderdetail
        this.orderDetailService.saveBatch(orderDetailList);
        //orderLogistics


        //根据收货地址id，以及用户id查询地址信息
        AddressDTO addressDTO = this.userClient.queryAddressById(orderFormDTO.getAddressId());

        OrderLogistics logistics = new OrderLogistics();
        BeanUtils.copyProperties(addressDTO, logistics);
        logistics.setOrderId(order.getOrderId());

        //保存收货物流地址信息
        this.orderLogisticsService.save(logistics);

        //throw new LyException(500, "故意捣乱");
         return order.getOrderId();
    }

    @Override
    public void handleNotify(Map<String, String> data) {
        // 1.业务标示校验
        payHelper.checkResultCode(data);
        // 2.签名校验
        payHelper.checkResponseSignature(data);

        // 3.订单状态校验（保证幂等，防止重复通知）
        String outTradeNo = data.get(ORDER_NO_KEY);
        String totalFee = data.get(TOTAL_FEE_KEY);
        if (StringUtils.isBlank(outTradeNo) || StringUtils.isBlank(totalFee)) {
            // 数据有误
            throw new RuntimeException("响应数据有误，订单金额或编号为空！");
        }
        Long orderId = Long.valueOf(outTradeNo);
        Order order = getById(orderId);
        if (order.getStatus().intValue() != 1) {
            // 说明订单已经支付过了，属于重复通知，直接返回
            return;
        }

        // 4.订单金额校验
        Long total = Long.valueOf(totalFee);
        if (!total.equals(1L/*order.getActualFee()*/)) {
            throw new RuntimeException("订单金额有误，我要报警了！");
        }

        // 5.修改订单状态，更新状态和支付时间两个字段
        update().set("status", OrderStatus.PAY_UP.getValue()).set("pay_time", new Date())
                // 条件包括订单id和订单状态必须为1，乐观锁保证幂等
                .eq("order_id", orderId).eq("status", OrderStatus.INIT.getValue()).update();
        log.info("处理微信支付通知成功！{}", data);
    }

    @Override
    public  void clearOrder() {

        //deadLine
        Date deadLine = DateTime.now().minusMinutes(5).toDate();

        //select * from tb_order where status = 1 and create_time < xxxx
        List<Order> orderList = query()
                .eq("status", 1)
                .lt("create_time", deadLine)
                .list();

        //有加库存的需求才操作
        if (!CollectionUtils.isEmpty(orderList)){
            //查询当前订单下所有的订单详情

            List<Long> orderIds = orderList
                    .stream()
                    .map(Order::getOrderId)
                    .collect(
                            Collectors.toList());

            //修改订单，批量关闭
            update().set("status",5).set("close_time",new Date())
                    .in("order_id",orderIds);

            Map<Long,Integer> cartsMap = new HashMap<>();

            //select * from orderDetails where order_id in #{xxxx}
            List<OrderDetail> orderDetails =
                            orderDetailService
                            .query()
                            .in("order_id",orderIds )
                            .list();

            for (OrderDetail orderDetail : orderDetails) {
                Long key = orderDetail.getSkuId();
                Integer num = orderDetail.getNum();

                //判断此商品是否存在过，如果存在，在修改数量
                if (cartsMap.containsKey(key)){
                    cartsMap.put(key,cartsMap.get(key)+num);
                }else{//否则直接添加
                    cartsMap.put(key,num);
                }
            }

            this.itemClient.plusStock(cartsMap);

        }

        //1,改变当前订单状态为5
        //2,库存还原

    }
}
